package com.yirui.serialcomm.core.protocol;

import com.fazecast.jSerialComm.SerialPort;
import com.yirui.serialcomm.core.Connector;
import com.yirui.serialcomm.core.util.HexUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author Dujie
 * @create 2025/8/5
 * @since 1.0.0
 */
@Slf4j
public class SerialCommServer extends AbstractServer{

    private ExecutorService readExecutorService;
    private ExecutorService writeExecutorService;
    private int maxBufferSize = 4096;
    private  SerialPort serialPort;
    private long writeTime;
    private long readTime;
    private final AtomicBoolean runState = new AtomicBoolean(true);
    public SerialCommServer(String serialComm) {
        this(SerialPort.getCommPort(serialComm));

    }

    public SerialCommServer(SerialPort serialPort) {
        this.serialPort = serialPort;
//        int coreSize = Runtime.getRuntime().availableProcessors();
//        executorService = new ThreadPoolExecutor(coreSize, coreSize*2,
//                60L, TimeUnit.SECONDS, new ArrayBlockingQueue(32),
//                new PoolNameFactory(serialComm+" Pool"),
//                new ThreadPoolExecutor.CallerRunsPolicy());
        // 使用线程池管理读写线程
        readExecutorService = Executors.newSingleThreadExecutor();
        writeExecutorService = Executors.newSingleThreadExecutor();
    }

//    private static final class PoolNameFactory implements ThreadFactory {
//        private final String name;
//
//        PoolNameFactory(String name) {
//            this.name = name;
//        }
//
//        @Override
//        public Thread newThread(Runnable runnable) {
//            Thread t = new Thread(runnable, this.name);
//            t.setDaemon(true);
//            return t;
//        }
//    }

    @Override
    public void start() throws Exception {

        // 1. 初始化串口
        serialPort.openPort();

        // 或者设置软件流控（XON/XOFF）
//        serialPort.setFlowControl(
//             SerialPort.FLOW_CONTROL_XONXOFF_IN_ENABLED |
//             SerialPort.FLOW_CONTROL_XONXOFF_OUT_ENABLED
//        );

        // 设置硬件流控（RTS/CTS）
        serialPort.setFlowControl(
                SerialPort.FLOW_CONTROL_RTS_ENABLED |
                        SerialPort.FLOW_CONTROL_CTS_ENABLED
        );

        // 设置串口参数，例如波特率、数据位、停止位等
        serialPort.setBaudRate(9600);
        serialPort.setNumDataBits(8);
        serialPort.setNumStopBits(SerialPort.ONE_STOP_BIT);
        serialPort.setParity(SerialPort.NO_PARITY);

        int readBufferSize = serialPort.getDeviceReadBufferSize();
        int writeBufferSize = serialPort.getDeviceWriteBufferSize();
        this.maxBufferSize = Math.max(readBufferSize, writeBufferSize);
        // 写入线程
        //从NET管道读取数据转发给串口设备
        writeExecutorService.submit(() -> {
            byte[] buffer = new byte[readBufferSize];
            try {
                Connector connector;
                while (runState.get()) {

                    connector = this.getConnector();
                    if(connector != null){
                        int bytesRead = connector.read(buffer); // 管道数据 → 处理
                        if (bytesRead > 0) {
                            writeTime = System.currentTimeMillis();
                            if(log.isDebugEnabled()) {
                                log.debug("从Net管道读取数据向串口设备写入数据: {}", HexUtils.toHexString(Arrays.copyOf(buffer, bytesRead)));
                            }
                           send(buffer, 0, bytesRead);
                        }
                    }


                }
            }catch (Exception ex){
                log.error("写操作异常:{}", ex);
                runState.set(false);
            }
        });


        // 读取线程
        //从串口设备中读取数据放入NET管道里，实现串口到NET的转发
        readExecutorService.submit(() -> {

            byte[] buffer = new byte[writeBufferSize];
            int bytesRead;
            try {
                Connector connector;
                while (runState.get()) {

                    connector = this.getConnector();
                    if(connector != null) {
                        bytesRead = serialPort.readBytes(buffer, buffer.length);
                        if (bytesRead > 0) {
                            readTime = System.currentTimeMillis();
                            if (log.isDebugEnabled()) {
                                log.debug("从串口设备读取数据向Net通道写入数据: {}", HexUtils.toHexString(Arrays.copyOf(buffer, bytesRead)));
                            }
                            connector.write(buffer, 0, bytesRead);
                        }
                    }

                }
            }catch (Exception ex){
                runState.set(false);
                log.error("读操作异常:{}", ex);
            }
            //重启服务
            serverDog();
        });

        log.info("[SerialCommServer] Server startup successful，port = {}" , serialPort.getSystemPortName());
//        SerialPort[] ports = SerialPort.getCommPorts();
//        log.info("###################当前可以串口列表#############################");
//        for (SerialPort port : ports) {
//            log.info("[{}]={}",port.getSystemPortName(),port.getDescriptivePortName());
//        }
//        log.info("#############################################################");

    }
    private void serverDog() {
//        try {
//            if (runState.get()) {
//                return;
//            }
//            Thread.sleep(30000);
//            runState.set(true);
//            start();
//        }catch (Exception ex){
//            log.error("重启服务异常:{}", ex);
//        }
    }

    @Override
    public void stop() {
        log.info("串口服务关闭！");
        runState.set(false);
       if(writeExecutorService!= null){
           writeExecutorService.shutdown();
       }
        if(readExecutorService!= null){
            readExecutorService.shutdown();
        }
       if(serialPort != null){
           serialPort.closePort();
           serialPort = null;
       }
       super.stop();

    }

    @Override
    public void send(ByteBuf buffer) {
        byte[] bf = ByteBufUtil.getBytes(buffer);
        send(bf, 0 , bf.length);
    }

    public void send(byte[] buffer, int offset, int len) {
        serialPort.writeBytes(buffer, len);
    }

    public int getMaxBufferSize() {
        return maxBufferSize;
    }

    public long getWriteTime() {
        return writeTime;
    }
    public long getReadTime() {
        return readTime;
    }
}
